package org.finesys.common.security.authentication.base;

import org.finesys.common.security.core.util.OAuth2EndpointUtils;
import org.finesys.common.security.core.util.SecurityUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 自定义模式认证转换器
 */
public abstract class OAuth2ResourceOwnerBaseAuthenticationConverter<T extends OAuth2ResourceOwnerBaseAuthenticationToken> implements AuthenticationConverter {
    /**
     * 是否支持此convert
     *
     * @param grantType 授权类型
     * @return
     */
    public abstract boolean support(String grantType);

    /**
     * 校验参数
     *
     * @param request 请求
     */
    public void checkParams(HttpServletRequest request) {

    }

    /**
     * 构建具体类型的token
     *
     * @param authentication
     * @param requestedScopes
     * @param additionalParameters
     * @return
     */
    public abstract T bulidToken(Authentication authentication, Set<String> requestedScopes, Map<String, Object> additionalParameters);

    /**
     * 验证功能
     */
    @Override
    public Authentication convert(HttpServletRequest request) {
        // grant_type (REQUIRED)
        String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
        if (!support(grantType)) {
            return null;
        }
        //获取请求参数
        MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
        // scope (OPTIONAL)
        String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE);
        if (StringUtils.hasText(scope) && parameters.get(OAuth2ParameterNames.SCOPE).size() != 1) {
            OAuth2EndpointUtils.throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.SCOPE, OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI);
        }
        //
        Set<String> requestScopes = null;
        if (StringUtils.hasText(scope)) {
            requestScopes = new HashSet<>(Arrays.asList(StringUtils.delimitedListToStringArray(scope, " ")));
        }
        // 校验个性化参数
        checkParams(request);
        // 获取当前已经认证的客户端信息
        Authentication authentication = SecurityUtils.getAuthentication();
        if (authentication == null) {
            OAuth2EndpointUtils.throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ErrorCodes.INVALID_CLIENT, OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI);
        }
        //扩展信息
        Map<String, Object> additionalParameters = parameters.entrySet().stream()
                .filter(e -> !e.getKey().equals(OAuth2ParameterNames.GRANT_TYPE)
                        && !e.getKey().equals(OAuth2ParameterNames.SCOPE))
                .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
        // 创建token
        return bulidToken(authentication, requestScopes, additionalParameters);
    }
}
